﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using btom = Microsoft.BizTalk.ExplorerOM;
using hito = HenIT.BizTalk.Objects;

namespace HenIT.BizTalk
{
    public partial class MainForm : Form
    {
        #region Constants
        private readonly int LOADINGIMAGE = 20;
        private readonly int NOTFOUNDIMAGE = 21;
        private readonly int APPLICATIONIMAGE = 0;
        private readonly int ASSEMBLIESIMAGE = 1;
        private readonly int ASSEMBLYIMAGE = 2;
        private readonly int PROPERTYIMAGE = 3;
        private readonly int SCHEMASIMAGE = 4;
        private readonly int SCHEMAIMAGE = 5;
        private readonly int MAPSIMAGE = 6;
        private readonly int MAPIMAGE = 7;
        private readonly int PIPELINESIMAGE = 8;
        private readonly int PIPELINEIMAGE = 9;
        private readonly int ORCHESTRATIONSIMAGE = 10;
        private readonly int ORCHESTRATIONIMAGE = 11;
        private readonly int PORTSIMAGE = 12;
        private readonly int PORTIMAGE = 13;
        private readonly int RECEIVEPORTSIMAGE = 14;
        private readonly int RECEIVEPORTIMAGE = 15;
        private readonly int RECEIVELOCATIONSIMAGE = 16;
        private readonly int RECEIVELOCATIONIMAGE = 17;
        private readonly int SENDPORTSIMAGE = 18;
        private readonly int SENDPORTIMAGE = 19;
        private readonly int REFERENCEAPPIMAGE = 23;
        private readonly int TRANSPORTIMAGE = 24;
        private readonly int NOTEQUALIMAGE = 25;

        //private readonly int MAXDISPLAYLENGTH = 150;
        #endregion

        private hito.BizTalkGroup group1 = new HenIT.BizTalk.Objects.BizTalkGroup();
        private hito.BizTalkGroup group2 = new HenIT.BizTalk.Objects.BizTalkGroup();

        public MainForm()
        {
            InitializeComponent();
        }

        #region Form events
        private void MainForm_Load(object sender, EventArgs e)
        {
            if (Properties.Settings.Default.NewVersion)
            {
                Properties.Settings.Default.Upgrade();
                Properties.Settings.Default.NewVersion = false;
                Properties.Settings.Default.Save();
            }
            if (Properties.Settings.Default.MainWindowSize != new Size(0, 0))
            {
                this.Size = Properties.Settings.Default.MainWindowSize;
                this.Location = Properties.Settings.Default.MainWindowLocation;
            }

            tvwCompare.Nodes.Clear();
            txtBTSGroup1.Text = Properties.Settings.Default.PreviousGroup1;
            txtBTSGroup2.Text = Properties.Settings.Default.PreviousGroup2;
            if (txtBTSGroup1.Text.Length > 0)
            {
                backgroundWorker1.RunWorkerAsync();
                cboApplication.Enabled = true;
                cmdLoadList.Enabled = true;
                cmdCompare.Enabled = true;
            }
        }
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.WindowState == FormWindowState.Normal)
            {
                Properties.Settings.Default.MainWindowSize = this.Size;
                Properties.Settings.Default.MainWindowLocation = this.Location;
            }
            Properties.Settings.Default.Save();
        } 

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            this.Invoke((MethodInvoker)delegate()
            {
                cboApplication.Text = "Loading...";
            }
            );
            System.Threading.Thread.Sleep(500);
            this.Invoke((MethodInvoker) delegate()
            {
                cboApplication.Text = "";
                cboApplication.Items.Add("<All>");
                if (Properties.Settings.Default.PreviousAppList != null)
                {
                    foreach (string appName in Properties.Settings.Default.PreviousAppList)
                    {
                        cboApplication.Items.Add(appName);
                    }
                }
            }
            );            
        }
        #endregion

        #region Button events
        private void cmdSelectBTS1_Click(object sender, EventArgs e)
        {
            BizTalkGroupSelect bizTalkGroupSelect = new BizTalkGroupSelect();
            if (txtBTSGroup1.Text.Contains("SERVER="))
            {
                bizTalkGroupSelect.SqlServer = txtBTSGroup1.Text.Substring(txtBTSGroup1.Text.IndexOf("SERVER=") + 7);
                bizTalkGroupSelect.SqlServer = bizTalkGroupSelect.SqlServer.Substring(0, bizTalkGroupSelect.SqlServer.IndexOf(";"));
            }
            if (txtBTSGroup1.Text.Contains("DATABASE="))
            {
                bizTalkGroupSelect.MgmtDb = txtBTSGroup1.Text.Substring(txtBTSGroup1.Text.IndexOf("DATABASE=") + 9);
            }
            if (bizTalkGroupSelect.ShowDialog() == DialogResult.OK)
            {
                txtBTSGroup1.Text = "SERVER=" + bizTalkGroupSelect.SqlServer + ";DATABASE=" + bizTalkGroupSelect.MgmtDb;
                LoadApplications();
                cboApplication.Enabled = true;
                cmdLoadList.Enabled = true;
                cmdCompare.Enabled = true;
            }
        }
        private void LoadApplications()
        {
            cboApplication.Items.Clear();
            Properties.Settings.Default.PreviousAppList = new System.Collections.Specialized.StringCollection();
            try
            {
                cboApplication.Items.Add("<All>");
                using (btom.BtsCatalogExplorer catalog = new btom.BtsCatalogExplorer())
                {
                    catalog.ConnectionString = txtBTSGroup1.Text + ";Integrated Security=SSPI";
                    foreach (btom.Application application in catalog.Applications)
                    {
                        if (!application.IsSystem)
                        {
                            cboApplication.Items.Add(application.Name);
                            Properties.Settings.Default.PreviousAppList.Add(application.Name);
                        }
                    }
                    Properties.Settings.Default.Save();
                }
            }
            catch { }
        }

        private void cmdSelectBTS2_Click(object sender, EventArgs e)
        {
            BizTalkGroupSelect bizTalkGroupSelect = new BizTalkGroupSelect();
            if (txtBTSGroup2.Text.Contains("SERVER="))
            {
                bizTalkGroupSelect.SqlServer = txtBTSGroup2.Text.Substring(txtBTSGroup1.Text.IndexOf("SERVER=") + 7);
                bizTalkGroupSelect.SqlServer = bizTalkGroupSelect.SqlServer.Substring(0, bizTalkGroupSelect.SqlServer.IndexOf(";"));
            }
            if (txtBTSGroup2.Text.Contains("DATABASE="))
            {
                bizTalkGroupSelect.MgmtDb = txtBTSGroup2.Text.Substring(txtBTSGroup2.Text.IndexOf("DATABASE=") + 9);
            }
            if (bizTalkGroupSelect.ShowDialog() == DialogResult.OK)
            {
                txtBTSGroup2.Text = "SERVER=" + bizTalkGroupSelect.SqlServer + ";DATABASE=" + bizTalkGroupSelect.MgmtDb;
            }
        }

        private void cmdSwap_Click(object sender, EventArgs e)
        {
            string tmp = txtBTSGroup1.Text;
            txtBTSGroup1.Text = txtBTSGroup2.Text;
            txtBTSGroup2.Text = tmp;
        }

        private void cmdCompare_Click(object sender, EventArgs e)
        {
            if (txtBTSGroup1.Text.Length == 0 || txtBTSGroup2.Text.Length == 0)
            {
                MessageBox.Show("You must specify both groups before comparing!", "Compare", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else if (txtBTSGroup1.Text == txtBTSGroup2.Text)
            {
                MessageBox.Show("You cannot compare a group with itself!", "Compare", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else 
            {
                try
                {
                    string applicationFilter = cboApplication.Text;
                    if (applicationFilter == "<All>")
                        applicationFilter = "";
                    if (CompareGroups(txtBTSGroup1.Text, txtBTSGroup2.Text, applicationFilter))
                    {
                        System.Threading.Thread.Sleep(500);
                        tvwCompare.Nodes.Clear();
                        System.Windows.Forms.Application.DoEvents();
                        Cursor.Current = Cursors.WaitCursor;

                        DisplayMatching(group1);
                        toolStripButtonReport.Enabled = true;
                        showReportToolStripMenuItem.Enabled = true;
                        Properties.Settings.Default.PreviousGroup1 = txtBTSGroup1.Text;
                        Properties.Settings.Default.PreviousGroup2 = txtBTSGroup2.Text;
                        Properties.Settings.Default.Save();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
        }

        private void cmdLoadList_Click(object sender, EventArgs e)
        {
            LoadApplications();
        }
        #endregion        

        #region Display differences
        private void DisplayMatching(hito.BizTalkGroup group)
        {
            foreach (hito.Application application in group.Applications)
            {
                TreeNode appNode = CreateNode(application.Name, APPLICATIONIMAGE);
                appNode.Tag = application;
                if (!application.Match)
                {
                    appNode.ImageIndex = NOTFOUNDIMAGE;
                    appNode.SelectedImageIndex = NOTFOUNDIMAGE;
                }
                else
                {
                    #region References
                    TreeNode referencesNode = CreateNode("References", REFERENCEAPPIMAGE);
                    appNode.Nodes.Add(referencesNode);                    
                    foreach (hito.StringMatch refApp in application.References)
                    {
                        referencesNode.Nodes.Add(CreateNodeMatch(refApp, APPLICATIONIMAGE));
                    }
                    referencesNode.Expand();
                    #endregion

                    #region Assemblies
                    TreeNode assembliesNode = CreateNode("Assemblies", ASSEMBLIESIMAGE);
                    appNode.Nodes.Add(assembliesNode);
                    foreach (hito.HitAssembly hitAssembly in application.Assemblies)
                    {
                        TreeNode assemblyNode = CreateNode(hitAssembly.DisplayName, ASSEMBLYIMAGE);
                        if (!hitAssembly.Match)
                        {
                            assemblyNode.ImageIndex = NOTFOUNDIMAGE;
                            assemblyNode.SelectedImageIndex = NOTFOUNDIMAGE;
                        }
                        else if (!hitAssembly.Version.Match || !hitAssembly.Version.Match)
                        {
                            assemblyNode.Nodes.Add(CreateNodeMatch("Version", hitAssembly.Version, PROPERTYIMAGE));
                            assemblyNode.Nodes.Add(CreateNodeMatch("Culture", hitAssembly.Culture, PROPERTYIMAGE));
                            assemblyNode.Expand();
                        }
                        else
                        {
                            #region Schemas
                            TreeNode schemasNode = CreateNode("Schemas", SCHEMASIMAGE);
                            assemblyNode.Nodes.Add(schemasNode);
                            foreach (hito.Schema schema in hitAssembly.Schemas)
                            {
                                TreeNode schemaNode = CreateNodeMatch(schema.Name, schema.Match, SCHEMAIMAGE);
                                schemasNode.Nodes.Add(schemaNode);
                                schemaNode.Nodes.Add(CreateNode(schema.MessageType, PROPERTYIMAGE));
                            }
                            schemasNode.Expand(); 
                            #endregion

                            #region Maps
                            TreeNode mapsNode = CreateNode("Maps", MAPSIMAGE);
                            assemblyNode.Nodes.Add(mapsNode);
                            foreach (hito.StringMatch map in hitAssembly.Maps)
                            {
                                TreeNode mapNode = CreateNodeMatch(map, MAPIMAGE);
                                mapsNode.Nodes.Add(mapNode);
                            }
                            mapsNode.Expand(); 
                            #endregion

                            #region Pipelines
                            TreeNode pipelinesNode = CreateNode("Pipelines", PIPELINESIMAGE);
                            assemblyNode.Nodes.Add(pipelinesNode);
                            foreach (hito.StringMatch pipeline in hitAssembly.Pipelines)
                            {
                                TreeNode pipelineNode = CreateNodeMatch(pipeline, PIPELINEIMAGE);
                                pipelinesNode.Nodes.Add(pipelineNode);
                            }
                            pipelinesNode.Expand(); 
                            #endregion

                            #region Orchestrations
                            TreeNode orchestrationsNode = CreateNode("Orchestrations", ORCHESTRATIONSIMAGE);
                            assemblyNode.Nodes.Add(orchestrationsNode);
                            foreach (hito.Orchestration orchestration in hitAssembly.Orchestrations)
                            {
                                TreeNode orchestrationNode = CreateNodeMatch(orchestration.Name, orchestration.Match, ORCHESTRATIONIMAGE);
                                if (orchestration.Match)
                                {
                                    TreeNode orchestrationHostNode = CreateNodeMatch("Host", orchestration.Host, PROPERTYIMAGE);
                                    orchestrationNode.Nodes.Add(orchestrationHostNode);

                                    TreeNode orchestrationPortsNode = CreateNode("Ports", PORTSIMAGE);
                                    orchestrationNode.Nodes.Add(orchestrationPortsNode);
                                    foreach (hito.StringMatch orchestrationPort in orchestration.Ports)
                                    {
                                        orchestrationPortsNode.Nodes.Add(CreateNodeMatch(orchestrationPort, PORTIMAGE));
                                    }
                                    orchestrationPortsNode.Expand();
                                    orchestrationNode.Expand();
                                }
                                orchestrationsNode.Nodes.Add(orchestrationNode);
                            }
                            orchestrationsNode.Expand(); 
                            #endregion

                            assemblyNode.Expand();
                        }
                        assembliesNode.Nodes.Add(assemblyNode);
                        assembliesNode.Expand();
                    } 
                    #endregion

                    #region Ports
                    TreeNode portsNode = CreateNode("Ports", PORTSIMAGE);
                    appNode.Nodes.Add(portsNode);

                    #region Receive ports
                    TreeNode receivePortsNode = CreateNode("Receive ports", RECEIVEPORTSIMAGE);
                    portsNode.Nodes.Add(receivePortsNode);
                    foreach (hito.ReceivePort receivePort in application.ReceivePorts)
                    {
                        TreeNode receivePortNode = CreateNodeMatch(receivePort.Name, receivePort.Match, RECEIVEPORTIMAGE);
                        receivePortsNode.Nodes.Add(receivePortNode);
                        if (receivePort.Match)
                        {
                            receivePortNode.Nodes.Add(CreateNodeMatch("Is two way", receivePort.IsTwoWay, PROPERTYIMAGE));
                            receivePortNode.Nodes.Add(CreateNodeMatch("Authentication type", receivePort.AuthenticationType, PROPERTYIMAGE));
                            receivePortNode.Nodes.Add(CreateNodeMatch("Route failed messages", receivePort.RouteFailedMessage, PROPERTYIMAGE));

                            #region Receive locations
                            TreeNode receiveLocationsNode = CreateNode("Receive locations", RECEIVELOCATIONSIMAGE);
                            receivePortNode.Nodes.Add(receiveLocationsNode);
                            foreach (hito.ReceiveLocation receiveLocation in receivePort.Receivelocations)
                            {
                                TreeNode receiveLocationNode = CreateNodeMatch(receiveLocation.Name, receiveLocation.Match, RECEIVELOCATIONIMAGE);
                                receiveLocationsNode.Nodes.Add(receiveLocationNode);
                                if (receiveLocation.Match)
                                {
                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("Transport type", receiveLocation.TransportType, PROPERTYIMAGE));

                                    #region Pipelines
                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("Receive pipeline", receiveLocation.ReceivePipeline, PROPERTYIMAGE));
                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("Receive pipeline data", receiveLocation.ReceivePipelineData, PROPERTYIMAGE));
                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("Receive handler host", receiveLocation.ReceiveHandlerHost, PROPERTYIMAGE));
                                    if (receivePort.IsTwoWay.Value)
                                    {
                                        receiveLocationNode.Nodes.Add(CreateNodeMatch("Send pipeline", receiveLocation.SendPipeline, PROPERTYIMAGE));
                                        receiveLocationNode.Nodes.Add(CreateNodeMatch("Send pipeline data", receiveLocation.SendPipelineData, PROPERTYIMAGE));
                                    } 
                                    #endregion

                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("Is Primary", receiveLocation.IsPrimary, PROPERTYIMAGE));

                                    #region Schedule
                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("Start date enabled", receiveLocation.StartDateEnabled, PROPERTYIMAGE));
                                    if (receiveLocation.StartDateEnabled.Value || receiveLocation.StartDateEnabled.Value2)
                                    {
                                        receiveLocationNode.Nodes.Add(CreateNodeMatch("Start date", receiveLocation.StartDate, PROPERTYIMAGE));
                                    }
                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("End date enabled", receiveLocation.EndDateEnabled, PROPERTYIMAGE));
                                    if (receiveLocation.EndDateEnabled.Value || receiveLocation.EndDateEnabled.Value2)
                                    {
                                        receiveLocationNode.Nodes.Add(CreateNodeMatch("End date", receiveLocation.EndDate, PROPERTYIMAGE));
                                    }
                                    receiveLocationNode.Nodes.Add(CreateNodeMatch("Service window enabled", receiveLocation.ServiceWindowEnabled, PROPERTYIMAGE));
                                    if (receiveLocation.ServiceWindowEnabled.Value || receiveLocation.ServiceWindowEnabled.Value2)
                                    {
                                        receiveLocationNode.Nodes.Add(CreateNodeMatch("From time", receiveLocation.FromTime, PROPERTYIMAGE));
                                        receiveLocationNode.Nodes.Add(CreateNodeMatch("To time", receiveLocation.ToTime, PROPERTYIMAGE));
                                    } 
                                    #endregion
                                    
                                }
                                receiveLocationNode.Expand();
                            }
                            receiveLocationsNode.Expand(); 
                            #endregion

                            #region Maps
                            if (receivePort.InboundMaps.Count > 0)
                            {
                                TreeNode inboundMapNode = CreateNode("Inbound maps", MAPIMAGE);
                                receivePortNode.Nodes.Add(inboundMapNode);
                                foreach (hito.StringMatch map in receivePort.InboundMaps)
                                {
                                    inboundMapNode.Nodes.Add(CreateNodeMatch(map, MAPIMAGE));
                                }
                                inboundMapNode.Expand();
                            }
                            if (receivePort.OutboundMaps.Count > 0)
                            {
                                TreeNode outboundMapNode = CreateNode("Outbound maps", MAPIMAGE);
                                receivePortNode.Nodes.Add(outboundMapNode);
                                foreach (hito.StringMatch map in receivePort.OutboundMaps)
                                {
                                    outboundMapNode.Nodes.Add(CreateNodeMatch(map, MAPIMAGE));
                                }
                                outboundMapNode.Expand();
                            } 
                            #endregion
                        }
                        receivePortNode.Expand();
                    }
                    receivePortsNode.Expand();
                    #endregion

                    #region Send ports
                    TreeNode sendPortsNode = CreateNode("Send ports", SENDPORTSIMAGE);
                    portsNode.Nodes.Add(sendPortsNode);
                    foreach (hito.SendPort sendPort in application.SendPorts)
                    {
                        TreeNode sendPortNode = CreateNodeMatch(sendPort.Name, sendPort.Match, SENDPORTIMAGE);
                        sendPortsNode.Nodes.Add(sendPortNode);
                        if (sendPort.Match)
                        {
                            sendPortNode.Nodes.Add(CreateNodeMatch("Is Dynamic", sendPort.IsDynamic, PROPERTYIMAGE));
                            sendPortNode.Nodes.Add(CreateNodeMatch("Is two way", sendPort.IsTwoWay, PROPERTYIMAGE));

                            #region Transports
                            if (!sendPort.IsDynamic.Value || !sendPort.IsDynamic.Value2)
                            {
                                TreeNode primaryTransportNode = CreateNode("Primary Transport", TRANSPORTIMAGE);
                                primaryTransportNode.Nodes.Add(CreateNodeMatch("Transport type", sendPort.PrimaryTransport.TransportType, PROPERTYIMAGE));
                                primaryTransportNode.Nodes.Add(CreateNodeMatch("Send handler host", sendPort.PrimaryTransport.SendHandlerHost, PROPERTYIMAGE));

                                sendPortNode.Nodes.Add(primaryTransportNode);

                                if (sendPort.SecondaryTransport.IsUsed.Value || !sendPort.SecondaryTransport.IsUsed.Match)
                                {
                                    TreeNode secondaryTransportNode = CreateNode("Secondary Transport", TRANSPORTIMAGE);
                                    secondaryTransportNode.Nodes.Add(CreateNodeMatch("Transport type", sendPort.SecondaryTransport.TransportType, PROPERTYIMAGE));
                                    secondaryTransportNode.Nodes.Add(CreateNodeMatch("Send handler host", sendPort.SecondaryTransport.SendHandlerHost, PROPERTYIMAGE));
                                    sendPortNode.Nodes.Add(secondaryTransportNode);
                                }
                                primaryTransportNode.Expand();
                            } 
                            #endregion

                            #region Pipelines
                            if (sendPort.IsTwoWay.Value || sendPort.IsTwoWay.Value2)
                            {
                                sendPortNode.Nodes.Add(CreateNodeMatch("Receive pipeline", sendPort.ReceivePipeline, PROPERTYIMAGE));
                                sendPortNode.Nodes.Add(CreateNodeMatch("Receive pipeline data", sendPort.ReceivePipelineData, PROPERTYIMAGE));
                            }
                            sendPortNode.Nodes.Add(CreateNodeMatch("Send pipeline", sendPort.SendPipeline, PROPERTYIMAGE));
                            sendPortNode.Nodes.Add(CreateNodeMatch("Send pipeline data", sendPort.SendPipelineData, PROPERTYIMAGE)); 
                            #endregion

                            sendPortNode.Nodes.Add(CreateNodeMatch("Priority", sendPort.Priority, PROPERTYIMAGE));
                            sendPortNode.Nodes.Add(CreateNodeMatch("Ordered delivery", sendPort.OrderedDelivery, PROPERTYIMAGE));
                            sendPortNode.Nodes.Add(CreateNodeMatch("Stop sending on failure", sendPort.StopSendingOnFailure, PROPERTYIMAGE));
                            sendPortNode.Nodes.Add(CreateNodeMatch("Route failed messages", sendPort.RouteFailedMessage, PROPERTYIMAGE));

                            #region Maps
                            if (sendPort.InboundMaps.Count > 0)
                            {
                                TreeNode inboundMapNode = CreateNode("Inbound maps", MAPIMAGE);
                                sendPortNode.Nodes.Add(inboundMapNode);
                                foreach (hito.StringMatch map in sendPort.InboundMaps)
                                {
                                    inboundMapNode.Nodes.Add(CreateNodeMatch(map, MAPIMAGE));
                                }
                                inboundMapNode.Expand();
                            }
                            if (sendPort.OutboundMaps.Count > 0)
                            {
                                TreeNode outboundMapNode = CreateNode("Outbound maps", MAPIMAGE);
                                sendPortNode.Nodes.Add(outboundMapNode);
                                foreach (hito.StringMatch map in sendPort.OutboundMaps)
                                {
                                    outboundMapNode.Nodes.Add(CreateNodeMatch(map, MAPIMAGE));
                                }
                                outboundMapNode.Expand();
                            } 
                            #endregion

                            sendPortNode.Nodes.Add(CreateNodeMatch("Filter", sendPort.Filter, PROPERTYIMAGE));
                        }
                        sendPortNode.Expand();
                    }
                    sendPortsNode.Expand();
                    #endregion

                    portsNode.Expand(); 
                    #endregion

                    appNode.Expand();
                }
                tvwCompare.Nodes.Add(appNode);
            }
            if (tvwCompare.Nodes.Count > 0)
                tvwCompare.Nodes[0].EnsureVisible();
        }
        private string LeftString(string str, int length)
        {
            if (str.Length > length)
                return str.Substring(0, length);
            else
                return str;
        }

        #region CreateNodes
        private TreeNode CreateNodeMatch(hito.StringMatch stringMatch, int imgIndex)
        {
            string str1 = stringMatch.Name.Length == 0 ? "N/A" : stringMatch.Name;
            string str2 = stringMatch.Name2.Length == 0 ? "N/A" : stringMatch.Name2;
            if (stringMatch.Match)
                return CreateNode(LeftString(str1, Properties.Settings.Default.MaxDisplayLength), imgIndex);
            else
                return CreateNode(LeftString(str1, Properties.Settings.Default.MaxDisplayLength) + " - " + LeftString(str2, Properties.Settings.Default.MaxDisplayLength), NOTFOUNDIMAGE);
        }
        private TreeNode CreateNodeMatch(string name, hito.IntMatch intMatch, int imgIndex)
        {
            if (intMatch.Match)
                return CreateNode(name + " : " + intMatch.Value.ToString(), imgIndex);
            else
                return CreateNode(name + " : " + intMatch.Value.ToString() + " - " + intMatch.Value2.ToString(), NOTEQUALIMAGE);//NOTFOUNDIMAGE);
        }
        private TreeNode CreateNodeMatch(string name, hito.StringMatch stringMatch, int imgIndex)
        {
            if (stringMatch.Match)
                return CreateNode(name + " : " + LeftString(stringMatch.Name, Properties.Settings.Default.MaxDisplayLength), imgIndex);
            else
                return CreateNode(name + " : " + LeftString(stringMatch.Name, Properties.Settings.Default.MaxDisplayLength) + " - " + LeftString(stringMatch.Name2, Properties.Settings.Default.MaxDisplayLength), NOTEQUALIMAGE); //NOTFOUNDIMAGE);
        }
        private TreeNode CreateNodeMatch(string name, hito.BoolMatch boolMatch, int imgIndex)
        {
            if (boolMatch.Match)
                return CreateNode(name + " : " + boolMatch.Value.ToString(), imgIndex);
            else
                return CreateNode(name + " : " + boolMatch.Value.ToString() + " - " + boolMatch.Value2.ToString(), NOTEQUALIMAGE); //NOTFOUNDIMAGE);
        }
        private TreeNode CreateNodeMatch(string name, hito.DateTimeMatch datetimeMatch, int imgIndex)
        {
            if (datetimeMatch.Match)
                return CreateNode(name + " : " + datetimeMatch.Value.ToString(), imgIndex);
            else
                return CreateNode(name + " : " + datetimeMatch.Value.ToString() + " - " + datetimeMatch.Value2.ToString(), NOTEQUALIMAGE); // NOTFOUNDIMAGE);
        }
        private TreeNode CreateNodeMatch(string name, bool match, int imgIndex)
        {
            if (match)
                return CreateNode(name, imgIndex);
            else
                return CreateNode(name, NOTFOUNDIMAGE);
        }
        private TreeNode CreateNode(string name, int imgIndex)
        {
            return new TreeNode(name, imgIndex, imgIndex);
        } 
        #endregion

        #endregion

        #region Compare objects
        private bool CompareGroups(string btsGroupConn1, string btsGroupConn2, string applicationFilter)
        {
            bool successDone = false;
            try
            {
                tvwCompare.Nodes.Clear();
                tvwCompare.Nodes.Add(CreateNode("Loading...", LOADINGIMAGE));
                System.Windows.Forms.Application.DoEvents();
                Cursor.Current = Cursors.WaitCursor;

                //Connecting to 2 BizTalk groups at the same time caused weird 'time-out' like problems.
                //Because of this a temporary set of objects are populated by each BtsCatalogExplorer
                // and then compared.
                group1 = new HenIT.BizTalk.Objects.BizTalkGroup();
                group2 = new HenIT.BizTalk.Objects.BizTalkGroup();
                using (btom.BtsCatalogExplorer catalog = new btom.BtsCatalogExplorer())
                {
                    catalog.ConnectionString = btsGroupConn1 + ";Integrated Security=SSPI";
                    group1.LoadGroupInfo(catalog, applicationFilter);
                    if (group1.LoadingErrors.Length > 0)
                    {
                        MessageBox.Show("There were errors loading details for group 1\r\n" + group1.LoadingErrors, "Loading errors", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }
                using (btom.BtsCatalogExplorer catalog = new btom.BtsCatalogExplorer())
                {
                    catalog.ConnectionString = btsGroupConn2 + ";Integrated Security=SSPI";
                    group2.LoadGroupInfo(catalog, applicationFilter);
                    if (group2.LoadingErrors.Length > 0)
                    {
                        MessageBox.Show("There were errors loading details for group 2\r\n" + group2.LoadingErrors, "Loading errors", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }

                tvwCompare.Nodes.Clear();
                tvwCompare.Nodes.Add(CreateNode("Comparing...", LOADINGIMAGE));
                System.Windows.Forms.Application.DoEvents();
                Cursor.Current = Cursors.WaitCursor;
                group1.CompareGroups(group2);
                successDone = true;
                if (group1.ComparingErrors.Length > 0)
                {
                    if (MessageBox.Show("There were errors comparing the 2 groups!\r\nContinue?\r\n" + group1.ComparingErrors, "Comparing errors", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                    {
                        successDone = false;
                    }
                }
                //CompareApplications(group1.Applications, group2.Applications);                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            Cursor.Current = Cursors.Default;

            return successDone;
        }
        #endregion        

        #region Toolbar buttons
        private void toolStripButtonCollapseAll_Click(object sender, EventArgs e)
        {
            tvwCompare.CollapseAll();
        }

        private void toolStripButtonExpandAll_Click(object sender, EventArgs e)
        {
            tvwCompare.ExpandAll();
            if (tvwCompare.Nodes.Count > 0)
                tvwCompare.Nodes[0].EnsureVisible();
        }

        private void toolStripButtonExpandNoMatch_Click(object sender, EventArgs e)
        {
            tvwCompare.CollapseAll();
            foreach (TreeNode appNode in tvwCompare.Nodes)
            {
                ExpandIfNoMatch(appNode);
            }
            if (tvwCompare.Nodes.Count > 0)
                tvwCompare.Nodes[0].EnsureVisible();
        }

        private bool ExpandIfNoMatch(TreeNode parentNode)
        {
            bool expandParent = false;
            foreach (TreeNode node in parentNode.Nodes)
            {
                if (node.ImageIndex == NOTFOUNDIMAGE || node.ImageIndex == NOTEQUALIMAGE)
                {
                    expandParent = true;
                }
                if (ExpandIfNoMatch(node))
                    expandParent = true;
            }
            if (expandParent)
                parentNode.Expand();
            return expandParent;
        } 
        #endregion

        #region Context menu events
        private void showReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Report.ReportWriter reportWriter = new Report.ReportWriter();
            reportWriter.CreateReport(group1, txtBTSGroup1.Text, txtBTSGroup2.Text);
        }
        #endregion

    }
}
